package com.cctc.juc.demo.Bitc.BwaitAndnotify.CLockSupport;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class LockSupportDemo {

    /**
     * 线程间通信方式之：基于线程等待与唤醒机制。
     * LockSupport 是 JUC 提供的线程等待与唤醒的工具类，实现原理与 Object 的 wait & notify[All] 类似。
     * - public static void park();
     * - public static void park(Object blocker);
     * - public static void parkNanos(long nanos);
     * - public static void parkUntil(long deadline);
     * - public static void parkNanos(Object blocker, long nanos);
     * - public static void unpark(Thread thread);
     * 二者的区别：
     * 1. Object 的 wait & notify[All] 方法需要在 synchronized 块中执行，而 LockSupport.park() 可以在任意地方执行；
     * 2. Object.wait() 方法抛出了中断异常，调用者必需要 [显式] 捕获或者再抛出；而 LockSupport.park() 不会抛出异常（仅设置了线程的中断标志），调用时不必需要 [显式] 捕获中断异常或者再抛出（当然，也可以根据需要主动判断是否出现了中断异常并处理）。
     * 此外，LockSupport.park() 与 Thread.sleep() 方法类似，都可以让当前线程休眠。
     * - public static native void sleep(long millis) throws InterruptedException;
     * 二者的区别：
     * 1. Thread.sleep() 方法只能自己醒过来（不会释放持有的锁）；而被 LockSupport 可以调用 LockSupport.unpark() 方法手动唤醒。
     * 2. 当被阻塞线程的 Thread.interrupt() 方法被调用时，被阻塞线程都会响应线程的中断信号，唤醒线程的执行，不同的是，Thread.sleep() 方法声明了中断异常，调用者必需要 [显式] 捕获或者再抛出；而 LockSupport.park() 不会抛出异常（仅设置了线程的中断标志），调用时不必需要 [显式] 捕获中断异常或者再抛出（当然，也可以根据需要主动判断 Thread.interrupted() 是否出现了中断异常并处理）。
     * 3. 此外，LockSupport 还允许设置一个 Blocker 对象，用来查看线程等待的原因。
     * 因此，与 Thread.sleep() 相比，LockSupport 可以更加精准、灵活的休眠、唤醒指定的线程。
     */

    public static class ChangeObjectThread extends Thread {
        public ChangeObjectThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            System.out.println("线程 [" + getName() + "] 被加入到 LockSupport 互斥锁的等待队列了");
            // 将当前线程加入到 LockSupport 互斥锁的等待队列
            LockSupport.park();
            // 如果当前线程在等待时被中断了，可以主动检测并处理，继续执行
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("线程 [" + getName() + "] 被中断了，执行中断处理逻辑，继续执行...");
            } else {
                // 如果当前线程被唤醒了，从 LockSupport 互斥锁的等待队列中被取出，重新抢锁，继续执行
                System.out.println("线程 [" + getName() + "] 被唤醒了，重新抢锁，继续执行...");
            }
        }
    }

    public static void main(String[] args) {
        ChangeObjectThread t1 = new ChangeObjectThread("thread-01");
        ChangeObjectThread t2 = new ChangeObjectThread("thread-02");
        try {
            // 启动 t1 线程
            t1.start();
            TimeUnit.SECONDS.sleep(1);

            // 启动 t2 线程
            t2.start();
            TimeUnit.SECONDS.sleep(1);

            // 中断 t1 线程
            t1.interrupt();

            // 唤醒 t2 线程
            LockSupport.unpark(t2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
